import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTextEdit, QFileDialog,
                             QMessageBox, QAction, QFontDialog, QColorDialog)
from PyQt5.QtGui import QIcon, QTextCharFormat, QFont, QColor
from PyQt5.QtCore import Qt, QSize


class Notepad(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.current_file = None

    def initUI(self):
        # 设置窗口标题和大小
        self.setWindowTitle("记事本")
        self.setGeometry(100, 100, 800, 600)

        # 创建中央文本编辑区域
        self.text_edit = QTextEdit()
        self.setCentralWidget(self.text_edit)

        # 创建菜单栏
        self.create_menus()

        # 创建工具栏
        self.create_toolbar()

        # 状态栏
        self.statusBar().showMessage('就绪')

    def create_menus(self):
        # 文件菜单
        file_menu = self.menuBar().addMenu('文件')

        new_action = QAction('新建', self)
        new_action.setShortcut('Ctrl+N')
        new_action.triggered.connect(self.new_file)
        file_menu.addAction(new_action)

        open_action = QAction('打开', self)
        open_action.setShortcut('Ctrl+O')
        open_action.triggered.connect(self.open_file)
        file_menu.addAction(open_action)

        save_action = QAction('保存', self)
        save_action.setShortcut('Ctrl+S')
        save_action.triggered.connect(self.save_file)
        file_menu.addAction(save_action)

        save_as_action = QAction('另存为', self)
        save_as_action.triggered.connect(self.save_as_file)
        file_menu.addAction(save_as_action)

        file_menu.addSeparator()

        exit_action = QAction('退出', self)
        exit_action.setShortcut('Ctrl+Q')
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)

        # 编辑菜单
        edit_menu = self.menuBar().addMenu('编辑')

        undo_action = QAction('撤销', self)
        undo_action.setShortcut('Ctrl+Z')
        undo_action.triggered.connect(self.text_edit.undo)
        edit_menu.addAction(undo_action)

        redo_action = QAction('重做', self)
        redo_action.setShortcut('Ctrl+Y')
        redo_action.triggered.connect(self.text_edit.redo)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction('剪切', self)
        cut_action.setShortcut('Ctrl+X')
        cut_action.triggered.connect(self.text_edit.cut)
        edit_menu.addAction(cut_action)

        copy_action = QAction('复制', self)
        copy_action.setShortcut('Ctrl+C')
        copy_action.triggered.connect(self.text_edit.copy)
        edit_menu.addAction(copy_action)

        paste_action = QAction('粘贴', self)
        paste_action.setShortcut('Ctrl+V')
        paste_action.triggered.connect(self.text_edit.paste)
        edit_menu.addAction(paste_action)

        select_all_action = QAction('全选', self)
        select_all_action.setShortcut('Ctrl+A')
        select_all_action.triggered.connect(self.text_edit.selectAll)
        edit_menu.addAction(select_all_action)

        # 格式菜单
        format_menu = self.menuBar().addMenu('格式')

        font_action = QAction('字体', self)
        font_action.triggered.connect(self.choose_font)
        format_menu.addAction(font_action)

        color_action = QAction('颜色', self)
        color_action.triggered.connect(self.choose_color)
        format_menu.addAction(color_action)

        # 帮助菜单
        help_menu = self.menuBar().addMenu('帮助')

        about_action = QAction('关于', self)
        about_action.triggered.connect(self.about)
        help_menu.addAction(about_action)

    def create_toolbar(self):
        toolbar = self.addToolBar('工具栏')
        toolbar.setIconSize(QSize(16, 16))

        # 新建按钮
        new_action = QAction('新建', self)
        new_action.triggered.connect(self.new_file)
        toolbar.addAction(new_action)

        # 打开按钮
        open_action = QAction('打开', self)
        open_action.triggered.connect(self.open_file)
        toolbar.addAction(open_action)

        # 保存按钮
        save_action = QAction('保存', self)
        save_action.triggered.connect(self.save_file)
        toolbar.addAction(save_action)

        toolbar.addSeparator()

        # 剪切按钮
        cut_action = QAction('剪切', self)
        cut_action.triggered.connect(self.text_edit.cut)
        toolbar.addAction(cut_action)

        # 复制按钮
        copy_action = QAction('复制', self)
        copy_action.triggered.connect(self.text_edit.copy)
        toolbar.addAction(copy_action)

        # 粘贴按钮
        paste_action = QAction('粘贴', self)
        paste_action.triggered.connect(self.text_edit.paste)
        toolbar.addAction(paste_action)

        toolbar.addSeparator()

        # 撤销按钮
        undo_action = QAction('撤销', self)
        undo_action.triggered.connect(self.text_edit.undo)
        toolbar.addAction(undo_action)

        # 重做按钮
        redo_action = QAction('重做', self)
        redo_action.triggered.connect(self.text_edit.redo)
        toolbar.addAction(redo_action)

    def new_file(self):
        if self.maybe_save():
            self.text_edit.clear()
            self.current_file = None
            self.setWindowTitle("记事本 - 新文件")

    def open_file(self):
        if self.maybe_save():
            file_path, _ = QFileDialog.getOpenFileName(self, "打开文件", "",
                                                       "文本文件 (*.txt);;所有文件 (*)")
            if file_path:
                try:
                    with open(file_path, 'r', encoding='utf-8') as file:
                        content = file.read()
                    self.text_edit.setText(content)
                    self.current_file = file_path
                    self.setWindowTitle(f"记事本 - {os.path.basename(file_path)}")
                except Exception as e:
                    QMessageBox.warning(self, "错误", f"无法打开文件: {str(e)}")

    def save_file(self):
        if self.current_file:
            try:
                content = self.text_edit.toPlainText()
                with open(self.current_file, 'w', encoding='utf-8') as file:
                    file.write(content)
                self.statusBar().showMessage('文件已保存')
            except Exception as e:
                QMessageBox.warning(self, "错误", f"无法保存文件: {str(e)}")
        else:
            self.save_as_file()

    def save_as_file(self):
        file_path, _ = QFileDialog.getSaveFileName(self, "另存为", "",
                                                   "文本文件 (*.txt);;所有文件 (*)")
        if file_path:
            try:
                content = self.text_edit.toPlainText()
                with open(file_path, 'w', encoding='utf-8') as file:
                    file.write(content)
                self.current_file = file_path
                self.setWindowTitle(f"记事本 - {os.path.basename(file_path)}")
                self.statusBar().showMessage('文件已保存')
            except Exception as e:
                QMessageBox.warning(self, "错误", f"无法保存文件: {str(e)}")

    def maybe_save(self):
        if not self.text_edit.document().isModified():
            return True

        ret = QMessageBox.warning(self, "记事本",
                                  "文档已被修改，是否保存更改？",
                                  QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)

        if ret == QMessageBox.Save:
            return self.save_file()
        elif ret == QMessageBox.Cancel:
            return False

        return True

    def choose_font(self):
        font, ok = QFontDialog.getFont(self.text_edit.font(), self)
        if ok:
            self.text_edit.setFont(font)

    def choose_color(self):
        color = QColorDialog.getColor(self.text_edit.textColor(), self)
        if color.isValid():
            self.text_edit.setTextColor(color)

    def about(self):
        QMessageBox.about(self, "关于记事本",
                          "这是一个使用 PyQt5 实现的简单记事本应用\n\n"
                          "支持基本的文本编辑功能，如新建、打开、保存文件，\n"
                          "以及剪切、复制、粘贴等操作。")

    def closeEvent(self, event):
        if self.maybe_save():
            event.accept()
        else:
            event.ignore()


def main():
    app = QApplication(sys.argv)
    notepad = Notepad()
    notepad.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()